package com.springcloud.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

import com.springcloud.util.model.BaseColorFeature;
import com.springcloud.util.model.BoolFeature;
import com.springcloud.util.model.CellEventEnhance;
import com.springcloud.util.model.HorizontalAlignment;
import com.springcloud.util.model.Margins;
import com.springcloud.util.model.NumberUtils;
import com.springcloud.util.model.Paddings;
import com.springcloud.util.model.TableEventEnhance;
import com.springcloud.util.model.VerticalAlignment;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * @Description: TODO
 * @Create by: 123
 * @Date: 2021/11/16 20:45
 */

@Data
public class PdfGenerateTool {

    private static final List<Float> DEFAULT_MAGINS = Arrays.asList(0f, 0f, 0f, 0f);
    private Document document;

    private PdfWriter writer;

    private byte[] data;

    private ByteOutputStream ous;

    private static String path = "C:\\Windows\\Fonts\\simfang.ttf";//windows里的字体资源路径
    public static BaseFont bf;

    static {
        try {
            bf = BaseFont.createFont(path, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public byte[] parse(String xml) {
        if (StringUtils.isBlank(xml)) return null;
        try {
            org.dom4j.Document document = DocumentHelper.parseText(xml.trim());
            Element root = document.getRootElement();
            this.handle(root, null, null);
            List<Element> elements = root.elements();
            if (CollectionUtils.isNotEmpty(elements)) {
                for (Element element : elements) {
                    this.handle(element, null, null);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.release();
        }
        return ous.getBytes();
    }

    private void handle(Element element, com.itextpdf.text.Element parentElement, Font font) throws DocumentException, IOException {
        String tag = element.getName();
        switch (tag) {
            case "page":
                this.initPage(element);
                break;
            case "table":
                this.buildTable(element, (PdfPCell) parentElement);
                break;
            case "cell":
                this.buildCell(element, (PdfPTable) parentElement);
                break;
            case "paragraph":
                this.buildParagraph(element, parentElement);
                break;
            case "image":
                this.buildImage(element, parentElement);
                break;
            case "chunk":
                this.buildChunk(element, parentElement, font);
                break;
            default:

        }
    }

    private void buildChunk(Element element, com.itextpdf.text.Element parentElement, Font font) throws IOException, DocumentException {
        String textTrim = element.getTextTrim();
        Chunk chunk = new Chunk(textTrim);
        chunk.setFont(font);
        if (StringUtils.isNotBlank(element.attributeValue("font-family"))) {
            chunk.setFont(buildFont(element));
        }
        if (parentElement == null) document.add(chunk);
        if (parentElement instanceof PdfPCell) {
            ((PdfPCell) parentElement).addElement(chunk);
        } else if (parentElement instanceof Paragraph) {
            ((Paragraph) parentElement).add(chunk);
        }
    }

    private Font buildFont(Element element) throws IOException, DocumentException {
        Float fontSize = NumberUtils.parseNumber(element.attributeValue("font-size"), 12f);
        int fontStyle = Font.NORMAL;
        if (new BoolFeature(element.attributeValue("font-bold"), false).isFeature()) {
            fontStyle = Font.BOLD;
        }
        if (new BoolFeature(element.attributeValue("font-italic"), false).isFeature()) {
            if (fontStyle == Font.NORMAL) {
                fontStyle = Font.ITALIC;
            } else {
                fontStyle = fontStyle | Font.ITALIC;
            }
        }
        String fontFamily = Optional.ofNullable(element.attributeValue("font-family")).orElse("宋体");


        FontFactory.register("C:\\Windows\\Fonts\\simsun.ttc", "宋体");
        FontFactory.register("C:\\Windows\\Fonts\\simkai.ttf", "楷体");
        BaseFont baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simkai.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        BaseColor color = new BaseColorFeature(element.attributeValue("font-color"), BaseColor.BLACK).getBaseColor();
        Font font = new Font(baseFont, fontSize, fontStyle, color);
        System.out.println(element.attributeValue("font-color"));
        return font;
    }

    private void buildImage(Element element, com.itextpdf.text.Element parentElement) {

    }

    private void buildParagraph(Element element, com.itextpdf.text.Element parentElement) throws DocumentException, IOException {
        String textTrim = element.getTextTrim();
        Paragraph paragraph = new Paragraph();

        Font paragraphFont = buildFont(element);
        paragraph.setAlignment(new HorizontalAlignment(element.attributeValue("h-align"), com.itextpdf.text.Element.ALIGN_UNDEFINED).getAlign());
        paragraph.setLeading(NumberUtils.parseNumber(element.attributeValue("leading"), paragraphFont.getSize()));
        paragraph.setFont(paragraphFont);
        if (StringUtils.isNotBlank(textTrim)) {
            paragraph.add(textTrim);
        }
        List<Element> chunks = element.elements();
        if (CollectionUtils.isNotEmpty(chunks)) {
            for (Element chunk : chunks) {
                buildChunk(chunk, parentElement, paragraphFont);
            }
        }
        if (parentElement == null) document.add(paragraph);
        if (parentElement instanceof PdfPCell) {
            ((PdfPCell) parentElement).addElement(paragraph);
        }
    }


    public void initPage(Element page) throws DocumentException {


        String pageSize = page.attributeValue("pageSize");
        Rectangle size = PageSize.A6;
        if (StringUtils.isNotBlank(pageSize)) {
            switch (pageSize) {
                case "A4":
                    size = PageSize.A4;
                    break;
                case "A6":
                    size = PageSize.A6;
                    break;
                default:

            }
        }
        document = new Document(size);
        // 上 右 下 左
        Margins margins1 = new Margins(page.attributeValue("margins"));
        document.setMargins(margins1.getMarginLeft(), margins1.getMarginRight(), margins1.getMarginTop(), margins1.getMarginBottom());
        ous = new ByteOutputStream();
        writer = PdfWriter.getInstance(document, ous);
        document.open();
    }

    public static void main(String[] args) {
    }

    public void release() {
        document.close();
        writer.close();
        ous.close();
    }

    /**
     * widthPercentage="100" relativeWidths="[1,2]" keepTogether="true"
     *
     * @param cell
     * @param tableElement
     */
    public void buildTable(Element tableElement, PdfPCell cell) {
        try {

            String widthPercentage = Optional.ofNullable(tableElement.attributeValue("widthPercentage")).orElse("100");
            List<Float> relativeWidths = JSON.parseObject(Optional.ofNullable(tableElement.attributeValue("relativeWidths")).orElse("[100]"), new TypeReference<List<Float>>() {
            });
            float[] widths = new float[relativeWidths.size()];
            for (int i = 0; i < relativeWidths.size(); i++) {
                widths[i] = relativeWidths.get(i);
            }
            PdfPTable table = new PdfPTable(widths.length);
            table.setWidthPercentage(NumberUtils.parseNumber(widthPercentage, 100f));
            table.setWidths(widths);
            table.setHorizontalAlignment(new HorizontalAlignment(tableElement.attributeValue("h-aligin")).getAlign());
            List<Element> cells = tableElement.elements();
            TableEventEnhance tableEventEnhance = new TableEventEnhance();
            if (CollectionUtils.isNotEmpty(cells)) {
                for (Element cellEle : cells) {
                    String name = cellEle.getName();
                    if (name.equals("table-event")) {
                        tableEventEnhance.addTableEvent(cellEle);
                    } else {
                        handle(cellEle, table, null);
                    }
                }
            }
            table.setTableEvent(tableEventEnhance);
            table.setKeepTogether(new BoolFeature(tableElement.attributeValue("keepTogether"), true).isFeature());
            if (cell != null) {
                cell.addElement(table);
            } else {
                document.add(table);
            }

        } catch (DocumentException | IOException e) {
            e.printStackTrace();
        }


    }

    /**
     * rowspan="2" colspan="2" fixedHeight="12.5" paddings="[1,2,3,4]" border="1" borderColor="#FFFF00"
     *
     * @param cellEle
     */
    public void buildCell(Element cellEle, PdfPTable table) {
        try {
            Optional<String> fixedHeight = Optional.ofNullable(cellEle.attributeValue("fixedHeight"));
            PdfPCell cell = new PdfPCell();
            if (fixedHeight.isPresent()) {
                cell.setFixedHeight(NumberUtils.parseNumber(fixedHeight.get(), 20f));
            }
            Paddings paddings = new Paddings(cellEle.attributeValue("paddings"));
            cell.setPaddingTop(paddings.getPaddingTop());
            cell.setPaddingLeft(paddings.getPaddingLeft());
            cell.setPaddingBottom(paddings.getPaddingBottom());
            cell.setPaddingRight(paddings.getPaddingRight());

            BaseColor borderColor = new BaseColorFeature(cellEle.attributeValue("border-color")).getBaseColor();
            if (borderColor != null) cell.setBorderColor(borderColor);

            BaseColor borderColorTop = new BaseColorFeature(cellEle.attributeValue("border-color-top")).getBaseColor();
            if (borderColorTop != null) cell.setBorderColorTop(borderColorTop);

            BaseColor borderColorLeft = new BaseColorFeature(cellEle.attributeValue("border-color-left")).getBaseColor();
            if (borderColorLeft != null) cell.setBorderColorLeft(borderColorLeft);

            BaseColor borderColorRight = new BaseColorFeature(cellEle.attributeValue("border-color-right")).getBaseColor();
            if (borderColorRight != null) cell.setBorderColorRight(borderColorRight);

            BaseColor borderColorBottom = new BaseColorFeature(cellEle.attributeValue("border-color-bottom")).getBaseColor();
            if (borderColorBottom != null) cell.setBorderColorBottom(borderColorBottom);



            Float borderWidth = NumberUtils.parseNumber(cellEle.attributeValue("border-width"));
            if (borderWidth != null) {
                cell.setBorderWidth(borderWidth);
            }else{
                cell.setBorderWidthTop(NumberUtils.parseNumber(cellEle.attributeValue("border-width-top"), 0f));
                cell.setBorderWidthRight(NumberUtils.parseNumber(cellEle.attributeValue("border-width-right"), 0f));
                cell.setBorderWidthBottom(NumberUtils.parseNumber(cellEle.attributeValue("border-width-bottom"), 0f));
                cell.setBorderWidthLeft(NumberUtils.parseNumber(cellEle.attributeValue("border-width-left"), 0f));
            }
            BaseColor backgroundColor = new BaseColorFeature(cellEle.attributeValue("background-color")).getBaseColor();
            if (backgroundColor != null) cell.setBackgroundColor(backgroundColor);

            String rowspan = cellEle.attributeValue("rowspan");
            if (StringUtils.isNotBlank(rowspan)) {
                cell.setRowspan(NumberUtils.parseInt(rowspan, 1));
            }
            String colspan = cellEle.attributeValue("colspan");
            if (StringUtils.isNotBlank(colspan)) {
                cell.setColspan(NumberUtils.parseInt(colspan, 1));
            }
            List<Element> elements = cellEle.elements();
            CellEventEnhance eventEnhance = new CellEventEnhance();
            if (CollectionUtils.isNotEmpty(elements)) {
                for (Element ele : elements) {
                    String eleName = ele.getName();
                    if (eleName.equalsIgnoreCase("cell-event")) {
                        eventEnhance.addCellEvent(ele);
                    } else {
                        handle(ele, cell, null);
                    }
                }
            }
            cell.setCellEvent(eventEnhance);
            cell.setHorizontalAlignment(new HorizontalAlignment(cellEle.attributeValue("h-align")).getAlign());
            //cell.setHorizontalAlignment(com.itextpdf.text.Element.ALIGN_MIDDLE);
            cell.setVerticalAlignment(new VerticalAlignment(cellEle.attributeValue("v-align")).getAlign());
            //cell.setVerticalAlignment(com.itextpdf.text.Element.ALIGN_MIDDLE);
            table.addCell(cell);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
